package cn.smallbun.screw.core.query.h2;

import cn.smallbun.screw.core.exception.QueryException;
import cn.smallbun.screw.core.mapping.Mapping;
import cn.smallbun.screw.core.metadata.Column;
import cn.smallbun.screw.core.metadata.Database;
import cn.smallbun.screw.core.metadata.PrimaryKey;
import cn.smallbun.screw.core.query.AbstractDatabaseQuery;
import cn.smallbun.screw.core.query.h2.model.H2ColumnModel;
import cn.smallbun.screw.core.query.h2.model.H2DatabaseModel;
import cn.smallbun.screw.core.query.h2.model.H2PrimaryKeyModel;
import cn.smallbun.screw.core.query.h2.model.H2TableModel;
import cn.smallbun.screw.core.util.Assert;
import cn.smallbun.screw.core.util.ExceptionUtils;
import cn.smallbun.screw.core.util.JdbcUtils;

import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import static cn.smallbun.screw.core.constant.DefaultConstants.PERCENT_SIGN;

/**
 * @author cuiyingfeng */
public class H2DataBaseQuery extends AbstractDatabaseQuery {

  /**
   * 构造函数
   *
   * @param dataSource {@link DataSource}
   */
  public H2DataBaseQuery(DataSource dataSource) {
    super(dataSource);
  }

  /**
   * 获取数据库
   *
   * @return {@link Database} 数据库信息
   */
  @Override
  public Database getDataBase() throws QueryException {
    H2DatabaseModel model = new H2DatabaseModel();
    // 当前数据库名称
    model.setDatabase(getCatalog());
    return model;
  }

  /**
   * 获取表信息
   *
   * @return {@link List} 所有表信息
   */
  @Override
  public List<H2TableModel> getTables() {
    ResultSet resultSet = null;
    try {
      // 查询
      resultSet =
          getMetaData().getTables(getCatalog(), getSchema(), PERCENT_SIGN, new String[] {"TABLE"});
      // 映射
      return Mapping.convertList(resultSet, H2TableModel.class);
    } catch (SQLException e) {
      throw ExceptionUtils.mpe(e);
    } finally {
      JdbcUtils.close(resultSet);
    }
  }

  /**
   * 获取列信息
   *
   * @param table {@link String} 表名
   * @return {@link List} 表字段信息
   * @throws QueryException QueryException
   */
  @Override
  public List<H2ColumnModel> getTableColumns(String table) throws QueryException {
    Assert.notEmpty(table, "Table name can not be empty!");
    ResultSet resultSet = null;
    try {
      // 查询
      resultSet = getMetaData().getColumns(getCatalog(), getSchema(), table, PERCENT_SIGN);
      // 映射
      List<H2ColumnModel> list=Mapping.convertList(resultSet, H2ColumnModel.class);
      filter(list);
      return list;

    } catch (SQLException e) {
      throw ExceptionUtils.mpe(e);
    } finally {
      JdbcUtils.close(resultSet);
    }
  }

  /**
   * h2数据库自增列默认值获取是一个序列对象的NEXT VALUE，这里将它设置为空字符串
   *
   * @param list {@link List} 表字段信息
   */
  private void filter(List<H2ColumnModel> list) {
    Assert.notEmpty(list, "list can not be empty!");
    list.stream().filter(var->("YES").equalsIgnoreCase(var.getIsAutoIncrement())).forEach(
            var->var.setColumnDef("")
    );
  }

  /**
   * 获取所有列信息
   *
   * @return {@link List} 表字段信息
   * @throws QueryException QueryException
   */
  @Override
  public List<? extends Column> getTableColumns() throws QueryException {
    // 获取全部列
    return getTableColumns(PERCENT_SIGN);
  }

  /**
   * 根据表名获取主键
   *
   * @param table {@link String}
   * @return {@link List}
   * @throws QueryException QueryException
   */
  @Override
  public List<? extends PrimaryKey> getPrimaryKeys(String table) throws QueryException {
    ResultSet resultSet = null;
    try {
      // 查询
      resultSet = getMetaData().getPrimaryKeys(getCatalog(), getSchema(), table);
      // 映射
      return Mapping.convertList(resultSet, H2PrimaryKeyModel.class);
    } catch (SQLException e) {
      throw ExceptionUtils.mpe(e);
    } finally {
      JdbcUtils.close(resultSet, this.connection);
    }
  }

  /**
   * 根据表名获取主键信息
   *
   * @return {@link List}
   * @throws QueryException QueryException
   */
  @Override
  public List<? extends PrimaryKey> getPrimaryKeys() throws QueryException {
    ResultSet resultSet = null;
    try {
      // 由于单条循环查询存在性能问题，所以这里通过自定义SQL查询数据库主键信息
      String sql =
          "select TABLE_CATALOG AS TABLE_CAT,NULL AS TABLE_SCHEM, TABLE_NAME,COLUMN_NAME,ORDINAL_POSITION AS KEY_SEQ," +
                  "'PRIMARY' AS PK_NAME from INFORMATION_SCHEMA.INDEXES where TABLE_CATALOG = '%s' AND PRIMARY_KEY= " +
                  "'TRUE' ORDER BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME,ORDINAL_POSITION;";
      // 拼接参数
      resultSet = prepareStatement(String.format(sql, getDataBase().getDatabase())).executeQuery();
      return Mapping.convertList(resultSet, H2PrimaryKeyModel.class);
    } catch (SQLException e) {
      throw new QueryException(e);
    } finally {
      JdbcUtils.close(resultSet);
    }
  }
}
